package com.example.readerapp.myandserver.mycontroller;

import android.os.Environment;
import com.example.readerapp.myandserver.mybookconfig.BookInfoTable;
import com.example.readerapp.myandserver.mybookconfig.MyBookConfig;
import com.example.readerapp.myandserver.util.*;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.yanzhenjie.andserver.annotation.*;
import com.yanzhenjie.andserver.http.HttpRequest;
import com.yanzhenjie.andserver.http.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.example.readerapp.myandserver.mybookconfig.MyBookConfig.*;
import static com.example.readerapp.myandserver.util.FindWordFromDir.ImitateFindWordFromFile;

//包名小写字母，类名驼峰格式，不然可能出错
//严格使用@RequestMappinghe@PostMapping不然传递数据会失败
//前端ajax请求的type要求严格，与上一条的注解对应
//直接请求，后台使用@GetMapping
@Controller
public class MyController
{

    String bookName="超神机械师.zip";
    String bookPath= basePath+bookName;
    BookInfoTable bookInfoTable=new BookInfoTable();

    @GetMapping(path ="/main")
    public String main() throws Exception
    {
        System.gc();
        initDir(bookInfoTable);
        return"/templates/main";
    }


    //初始化主页书籍列表
    @PostMapping("/getBookList")
    @ResponseBody
    public String bookList()
    {
        System.gc();
        initDir(bookInfoTable);//不加会出现奇怪的使用错误

        File fq=new File(basePath);
       // System.out.println("请求"+fq.getAbsolutePath());
        List<File> list= FileUtil.getFileSort(fq.getAbsolutePath());
        String book="";
        for(int i=0;i<list.size();i++)
        {
            //System.out.println("修改时间"+list.get(i).lastModified());
            book=book+list.get(i).getName().replace(".zip","")+"\n";

        }
        return book;
    }

    @GetMapping(path = "/lookbook")//这里必须用get
    public String index()
    {
        System.gc();
        return "/templates/lookbook";

    }
    //存储前台发送的用户正在读哪本书
    @PostMapping("/initBook")
    @ResponseBody
    public void initBook(HttpRequest request)
    {
        String getBookName= request.getParameter("bookName");
        System.out.println("获取"+getBookName);
        if (getBookName != null)
        {
         //   System.out.println("获取："+getBookName);
            bookName = getBookName + ".zip";
            bookPath=basePath+bookName;
            File f=new File(bookPath);
            f.setLastModified(new Date().getTime());

        }
        else
        {
            System.out.println("获取空值");
        }

    }
    @PostMapping("/getCurrentPageNumber")
    @ResponseBody
    public int getCurrentPageNumber()

    {
        System.gc();
        int number=1;
        try{
            //number= FormatBookUtil.getCurrentPageNumber(bookPath);
            number=FormatBookUtil.getCurrentPageNumber(bookInfoTable,basePath,bookName);
            System.out.println();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return number;
    }
    //获取当前书籍的全部页面
    @PostMapping("/getAllPageNumber")
    @ResponseBody
    public int getAllPageNumber()
    {
        System.gc();
        int number=0;
        try{
            number=FormatBookUtil.getAllPageNumber(bookPath);
          //  System.out.println("获取"+number);
        }
        catch (Exception e)
        {
            System.out.println("获取书籍页码异常"+e.getMessage());
            e.printStackTrace();
        }
        return number;
    }


    @PostMapping("/getPage")
    @ResponseBody
    public String getPageByNumber(HttpRequest request)
    {
        System.gc();
        int currentPageNumber= Integer.parseInt(request.getParameter("currentPageNumber"));
        String html="";
        try
        {
            html= FormatBookUtil.getBookPage(bookPath, currentPageNumber);
            ExecutorService executorService= Executors.newCachedThreadPool();
            //根据请求的页码，更新页码，后端不负责currentPageNumber++
            executorService.execute(new writePageNumber(basePath,bookName,currentPageNumber));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return html;
    }
    @PostMapping("/getPageNoRefreshPageNumber")
    @ResponseBody
    public String getPageNoRefresh(HttpRequest request)
    {
        System.gc();
        int currentPageNumber= Integer.parseInt(request.getParameter("i"));
        String html="";
        try
        {
            html= FormatBookUtil.getBookPage(bookPath, currentPageNumber);

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return html;
    }

    //没用了
    //判断十分耗时的写入书籍当前页码操作有没有结束。那个函数是synchronized的
    @PostMapping("/canExit")
    @ResponseBody
    public String isOver()
    {
        try
        {
            //一定会报错
          //  ZipUtil.writeTextIntoZipFile(null,"","",false);
            FormatBookUtil.setCurrentPageNumber(bookInfoTable, "", "", 0);
        }
        catch (Exception e)
        {
            return "可安全退出程序";
        }
        return "做个样子";
    }

    //查询书籍页面背景颜色、字体颜色等信息
    @PostMapping("/getSettings")
    @ResponseBody
    public String getSettings()
    {
        String backgroundColor=bookInfoTable.findBackgroundColorByBookName(bookName);
        String fonColor=bookInfoTable.findFontColorByBookName(bookName);
        String fontSize = bookInfoTable.findFontSizeByBookName(bookName);
        bookInfoTable.queryAll();
        System.out.println("测试测试是"+backgroundColor+fonColor+fontSize);
        return backgroundColor+"\n"+fonColor+"\n"+fontSize;
    }
    //更新书籍页面背景颜色、字体颜色等信息
    @PostMapping("/updateSettings")
    public void updateSettings(HttpRequest httpRequest)
    {
        String backgroundColor=httpRequest.getParameter("backgroundColor");
        String fonColor=httpRequest.getParameter("fontColor");
        String fontSize=httpRequest.getParameter("fontSize");
        System.out.println("更新："+backgroundColor+fonColor+fontSize);
        try
        {
            bookInfoTable.updateBackgroundColorByBookName(bookName, backgroundColor);
            bookInfoTable.updateFontColorByBookName(bookName, fonColor);
            bookInfoTable.updateFontSizeByBookName(bookName,fontSize);
        }catch (Exception e)
        {
            System.out.println("更新数据库异常");
            e.printStackTrace();
        }
     //   System.out.println("更新后：");
       // bookInfoTable.queryAll();
    }
    @PostMapping("/getTranslateFromDic")
    @ResponseBody
    public String getTranslateFromDic(HttpRequest request){
        System.gc();
        String findFromDir="<p>本地词典查询结果:</p>";
        String text=request.getParameter("text");
       // System.out.println("上传查询:"+text);
        findFromDir = getWordFromDic(findFromDir, text);
        return findFromDir;
    }

    //上传完了之后看一下pdf多少页，用户后面获取转换进度
    int pageNumber=0;

    //前端使用ajax异步上传，不能保证上传顺序,此变量用于记录已经上传多少数据块
    Integer haveUploadChunk=0;
    //将上传的数据端按照<起始位置，数据内容>格式存储
    Map<Long,byte[]> cache=new HashMap<>();
    /*切割上传文件*/
    @PostMapping("/upload")
    @ResponseBody
    public String breakPointUploadFileDo(HttpRequest request,@RequestParam(name = "file")  MultipartFile file) {
        long startLength= Long.parseLong(request.getParameter("startLength"));//本数据块在整个文件的起始位置
        int currentChunk= Integer.parseInt(request.getParameter("currentChunk"));//当前是第几个数据块
        int totalChunk= Integer.parseInt(request.getParameter("totalChunk"));//共有多少数据块
        String fileName=request.getParameter("fileName");
       // MultipartFile file= requestFile.getFile("file");
        System.out.println("开始上传");
        System.out.println(fileName + ":当前数据块：:" + currentChunk+" 总计数据块："+totalChunk);

        if (file.getSize() <= 0) {
            System.out.println("无文件上传");
            return "请选择上传的文件！";
        }
        String pdfPath=tempPdfPath+fileName;
        File f=new File(tempPdfPath);
        if(!f.exists())
            f.mkdir();
        try
        {
            //将转换好的文件片段保存
            cache.put(startLength,getByteFromInputStream(file.getStream()));

            synchronized (haveUploadChunk)
            {
                haveUploadChunk=(int)haveUploadChunk+1;
            }
            System.out.println("已经保存个数："+haveUploadChunk+" "+"总计数："+totalChunk);
            if(haveUploadChunk==totalChunk)//所有数据均已上传结束
            {
                Set<Map.Entry<Long,byte[]>> set=cache.entrySet();
                List<Map.Entry<Long,byte[]>> list=new ArrayList<>(set);
                //按键值由小到大排序
                Collections.sort(list, new Comparator<Map.Entry<Long, byte[]>>()
                {
                    @Override
                    public int compare(Map.Entry<Long, byte[]> o1, Map.Entry<Long, byte[]> o2)
                    {
                        return (int) (o2.getKey()- o1.getKey());//由小到大排序
                    }
                });
                RandomAccessFile writeFile = new RandomAccessFile(pdfPath, "rw");
                for(Map.Entry<Long, byte[]> c:list)
                {
                    writeFile.seek(c.getKey());
                    writeFile.write(c.getValue(),0,c.getValue().length);
                }
                writeFile.close();
                synchronized ( haveUploadChunk)
                {
                    haveUploadChunk=0;//!!!!!!
                }

                cache=null;
                cache=new HashMap<>();//!!!!!!
                System.out.println("文件上传结束,开始转换");
                try
                {
                    PdfReader pdfReader=new PdfReader(pdfPath);
                    com.itextpdf.kernel.pdf.PdfDocument pdfDocument = new PdfDocument(pdfReader);
                     pageNumber = pdfDocument.getNumberOfPages();
                    pdfReader.close();
                    pdfDocument.close();

                    //System.out.println("文件"+fileName);
                    fileName=fileName.replace(".pdf",".zip").replaceAll("'","‘").replaceAll("\"","”");
                    FormatBookUtil.createFormatBookForPurifyWordPdf(pdfPath,basePath+fileName,tempFilePath);
                    System.out.println("控制器结束转换"+new SimpleDateFormat("hh:mm:ss").format(new Date()));
                    pageNumber=0;
                    FormatBookUtil.addBookConfig(bookInfoTable,basePath,fileName,1);

                    //FormatBookUtil.createFormatBook(pdfPath, basePath + fileName.replace(".pdf", ".zip"), tempFilePath);
                }catch (Exception e)
                {
                    System.out.println("文件转换出错"+e.getMessage());
                    e.printStackTrace();
                    return "allSuccess";

                }finally
                {
                 /*File pdf=new File(pdfPath);
                    if(!pdf.delete())
                    {
                        System.out.println("pdf文件删除失败");
                    }*/

                    ExecutorService executorService=Executors.newCachedThreadPool();
                    executorService.execute(new deleteTempFile(tempPdfPath,tempFilePath));
                    executorService.shutdown();
                }
                System.out.println("控制器结束转换，向前端返回"+new SimpleDateFormat("hh:mm:ss").format(new Date()));

                return "allSuccess";
            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return "上传文件成功";
    }
    private byte[] getByteFromInputStream(InputStream iStream) throws IOException
    {
        System.gc();
        List<byte[]> chunkCache=new ArrayList<>();
        //将文件片段转换为byte[]
        while (true)
        {
            int len = 0;
            byte[] arr = new byte[1024];
            if((len=iStream.read(arr))!=-1)
                chunkCache.add(arr);
            else
                break;
        };
        iStream.close();
        int chunkLength=0;
        for(int i=0;i< chunkCache.size();i++)
        {
            chunkLength=chunkLength+chunkCache.get(i).length;
        }
        byte[] chunk=new byte[chunkLength];
        int index=0;
        for(int i=0;i<chunkCache.size();i++)
        {
            for(int j=0;j<chunkCache.get(i).length;j++)
            {
                chunk[index]=chunkCache.get(i)[j];
                index++;
            }
        }
        return chunk;
    }

    @GetMapping("/getProgress")
    @ResponseBody
    public String getProgress()
    {
        //System.out.println("请求");

        File f=new File(tempFilePath);
        if(f.exists()&&pageNumber!=0)
        {
            float c = 0;
            File[] list = f.listFiles();
            for (int i = 0; i < list.length; i++)
            {
                c = c + list[i].list().length;
                //  return c+"/"+pageNumber+":"+(int)(c/pageNumber)*100+"%";
            }
            if(pageNumber==0)
                return "" + (int) c + "\n" + pageNumber + "\n" + "后处理";

            if(c<=pageNumber&&(c / pageNumber)<=1.0)
                return "" + (int) c + "\n" + pageNumber + "\n" + (c / pageNumber) * 100 + "%";
            else
                return "" + (int) pageNumber + "\n" + pageNumber + "\n" +100 + "%";
        }
        else
            return "0\n0\n0%";
    }

}

class deleteTempFile extends Thread
{
    String tempPdfPath;
    String tempFilePath;
    deleteTempFile(String tempPdfPath,String tempFilePath)
    {
        this.setPriority(MIN_PRIORITY);//!!!!!!!!!可能导致主线程阻塞
        this.tempFilePath=tempFilePath;
        this.tempPdfPath=tempPdfPath;
    }
    @Override
    public void run()
    {
        FileUtil.deleteFile(new File(tempPdfPath));
        FileUtil.deleteFile(new File(tempFilePath));
    }
}
class writePageNumber extends Thread
{
      String bookName;
    String basePath;
    int currentPageNumber;
    writePageNumber(String basePath,String bookName,int currentPageNumber)
    {
        this.setPriority(MIN_PRIORITY);//!!!!!!!
        this.currentPageNumber=currentPageNumber;
        this.bookName=bookName;
        this.basePath=basePath;
    }

    @Override
    public void run()
    {
        try
        {

            FormatBookUtil.setCurrentPageNumber(new BookInfoTable(),basePath,bookName,currentPageNumber);
        }
        catch (Exception e)
        {
            System.out.println("写入页码异常");
            e.printStackTrace();
        }

    }
}
